home *** CD-ROM | disk | FTP | other *** search
/ Aminet 1 / Aminet - June 1993 [Walnut Creek].iso / usenet / sources / volume2 / util / wns < prev   
Encoding:
Internet Message Format  |  1988-10-20  |  52.1 KB

  1. Path: xanth!mcnc!rutgers!mit-eddie!ll-xn!adelie!infinet!ulowell!page
  2. From: page@swan.ulowell.edu (Bob Page)
  3. Newsgroups: comp.sources.amiga
  4. Subject: v02i001:  Windowed search (context grep)
  5. Message-ID: <9708@swan.ulowell.edu>
  6. Date: 19 Oct 88 00:05:16 GMT
  7. Organization: University of Lowell, Computer Science Dept.
  8. Lines: 2143
  9. Approved: page@swan.ulowell.edu
  10.  
  11. Submitted-by: mrr@amanpt1.zone1.com (Mark Rinfret)
  12. Posting-number: Volume 2, Issue 1
  13. Archive-name: util/wns
  14.  
  15. Here's a little search utility which appeared in one of the major
  16. sources groups recently (unix? misc?).  I made some minor changes to
  17. the program proper and added in some regular expression stuff that I
  18. had with a copy of NGrep.  I can't take credit for anything original
  19. here, but it was an easy port so I thought I'd pass it along.
  20.  
  21. Mark Rinfret, 10/18/88
  22. ----------------------Apply Scissors Here-------------------------------
  23. #! /bin/sh
  24. # This is a shell archive.  Remove anything before this line, then unpack
  25. # it by saving it into a file and typing "sh file".  To overwrite existing
  26. # files, type "sh file -c".  You can also feed this as standard input via
  27. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  28. # will see the following message at the end:
  29. #        "End of archive 1 (of 1)."
  30. # Contents:  Makefile regexp.h regmagic.h regerror.c regexp.c wns.c
  31. #   wns.man wns.1
  32. # Wrapped by mrr@mrramiga on Sun Oct  9 21:50:20 1988
  33. # This shar was created for Amiga and may have pathnames which
  34. # are incompatible with Unix.  Replace colon (:) with slash (/)
  35. # in offending pathnames. 
  36. if test -f Makefile -a "${1}" != "-c" ; then 
  37.   echo shar: Will not over-write existing file \"Makefile\"
  38. else
  39. echo shar: Extracting \"Makefile\" \(675 characters\)
  40. sed "s/^X//" >Makefile <<'END_OF_Makefile'
  41. X# Makefile for wns
  42. X#
  43. XCC = cc
  44. X
  45. X# Define in CFLAGS:
  46. X#    SYSINC    if include file hierarchy includes the sys/ directory
  47. X#    REGEX    if using berkeley-style re_exec() and re_comp()
  48. X#    REGCMP    if using regcmp() and regex()
  49. X#    REGCOMP if using regcomp() and regexec()
  50. X#    OS_UNIX if running under unix (or AmigaDOS)
  51. X#    AMIGA   if running under AmigaDOS
  52. X#    OS_CPM    if running under CP/M80
  53. X#    STRCSPN if you need the strcspn() function.
  54. X#
  55. X#
  56. X#CFLAGS=-DOS_UNIX -DREGCMP -DSYSINC
  57. XCFLAGS=-DOS_UNIX -DAMIGA -DREGCOMP -DSTRCSPN -n
  58. X#
  59. X# Define LIBS to reflect the librar[y][ies] needed to fetch the r/e routines.
  60. X#
  61. XLIBS=-lc
  62. X
  63. X#
  64. XWNSOBJS=wns.o regexp.o regerror.o
  65. X
  66. Xwns:    $(WNSOBJS)
  67. X    ln $(WNSOBJS) $(LIBS) -o wns
  68. END_OF_Makefile
  69. if test 675 -ne `wc -c <Makefile`; then
  70.     echo shar: \"Makefile\" unpacked with wrong size!
  71. fi
  72. # end of overwriting check
  73. fi
  74. if test -f regexp.h -a "${1}" != "-c" ; then 
  75.   echo shar: Will not over-write existing file \"regexp.h\"
  76. else
  77. echo shar: Extracting \"regexp.h\" \(574 characters\)
  78. sed "s/^X//" >regexp.h <<'END_OF_regexp.h'
  79. X/*
  80. X * Definitions etc. for regexp(3) routines.
  81. X *
  82. X * Caveat:  this is V8 regexp(3) [actually, a reimplementation thereof],
  83. X * not the System V one.
  84. X */
  85. X#define NSUBEXP  10
  86. Xtypedef struct regexp {
  87. X    char *startp[NSUBEXP];
  88. X    char *endp[NSUBEXP];
  89. X    char regstart;        /* Internal use only. */
  90. X    char reganch;        /* Internal use only. */
  91. X    char *regmust;        /* Internal use only. */
  92. X    int regmlen;        /* Internal use only. */
  93. X    char program[1];    /* Unwarranted chumminess with compiler. */
  94. X} regexp;
  95. X
  96. Xextern regexp *regcomp();
  97. Xextern int regexec();
  98. Xextern void regsub();
  99. Xextern void regerror();
  100. END_OF_regexp.h
  101. if test 574 -ne `wc -c <regexp.h`; then
  102.     echo shar: \"regexp.h\" unpacked with wrong size!
  103. fi
  104. # end of overwriting check
  105. fi
  106. if test -f regmagic.h -a "${1}" != "-c" ; then 
  107.   echo shar: Will not over-write existing file \"regmagic.h\"
  108. else
  109. echo shar: Extracting \"regmagic.h\" \(153 characters\)
  110. sed "s/^X//" >regmagic.h <<'END_OF_regmagic.h'
  111. X/*
  112. X * The first byte of the regexp internal "program" is actually this magic
  113. X * number; the start node begins in the second byte.
  114. X */
  115. X#define    MAGIC    0234
  116. END_OF_regmagic.h
  117. if test 153 -ne `wc -c <regmagic.h`; then
  118.     echo shar: \"regmagic.h\" unpacked with wrong size!
  119. fi
  120. # end of overwriting check
  121. fi
  122. if test -f regerror.c -a "${1}" != "-c" ; then 
  123.   echo shar: Will not over-write existing file \"regerror.c\"
  124. else
  125. echo shar: Extracting \"regerror.c\" \(170 characters\)
  126. sed "s/^X//" >regerror.c <<'END_OF_regerror.c'
  127. X#include <stdio.h>
  128. X
  129. Xvoid
  130. Xregerror(s)
  131. Xchar *s;
  132. X{
  133. X#ifdef ERRAVAIL
  134. X    error("regexp: %s", s);
  135. X#else
  136. X    fprintf(stderr, "regexp(3): %s", s);
  137. X    exit(1);
  138. X#endif
  139. X    /* NOTREACHED */
  140. X}
  141. END_OF_regerror.c
  142. if test 170 -ne `wc -c <regerror.c`; then
  143.     echo shar: \"regerror.c\" unpacked with wrong size!
  144. fi
  145. # end of overwriting check
  146. fi
  147. if test -f regexp.c -a "${1}" != "-c" ; then 
  148.   echo shar: Will not over-write existing file \"regexp.c\"
  149. else
  150. echo shar: Extracting \"regexp.c\" \(27732 characters\)
  151. sed "s/^X//" >regexp.c <<'END_OF_regexp.c'
  152. X/*
  153. X * regcomp and regexec -- regsub and regerror are elsewhere
  154. X *
  155. X *    Copyright (c) 1986 by University of Toronto.
  156. X *    Written by Henry Spencer.  Not derived from licensed software.
  157. X *
  158. X *    Permission is granted to anyone to use this software for any
  159. X *    purpose on any computer system, and to redistribute it freely,
  160. X *    subject to the following restrictions:
  161. X *
  162. X *    1. The author is not responsible for the consequences of use of
  163. X *        this software, no matter how awful, even if they arise
  164. X *        from defects in it.
  165. X *
  166. X *    2. The origin of this software must not be misrepresented, either
  167. X *        by explicit claim or by omission.
  168. X *
  169. X *    3. Altered versions must be plainly marked as such, and must not
  170. X *        be misrepresented as being the original software.
  171. X *
  172. X * Beware that some of this code is subtly aware of the way operator
  173. X * precedence is structured in regular expressions.  Serious changes in
  174. X * regular-expression syntax might require a total rethink.
  175. X
  176. X * 10/09/88 - This code was altered by Mark R. Rinfret for compatibility
  177. X * with the Amiga. (mrr@amanpt1.ZONE1.COM)
  178. X */
  179. X#include <stdio.h>
  180. X#include "regexp.h"
  181. X#include "regmagic.h"
  182. X
  183. X
  184. X/*
  185. X * The "internal use only" fields in regexp.h are present to pass info from
  186. X * compile to execute that permits the execute phase to run lots faster on
  187. X * simple cases.  They are:
  188. X *
  189. X * regstart    char that must begin a match; '\0' if none obvious
  190. X * reganch    is the match anchored (at beginning-of-line only)?
  191. X * regmust    string (pointer into program) that match must include, or NULL
  192. X * regmlen    length of regmust string
  193. X *
  194. X * Regstart and reganch permit very fast decisions on suitable starting points
  195. X * for a match, cutting down the work a lot.  Regmust permits fast rejection
  196. X * of lines that cannot possibly match.  The regmust tests are costly enough
  197. X * that regcomp() supplies a regmust only if the r.e. contains something
  198. X * potentially expensive (at present, the only such thing detected is * or +
  199. X * at the start of the r.e., which can involve a lot of backup).  Regmlen is
  200. X * supplied because the test in regexec() needs it and regcomp() is computing
  201. X * it anyway.
  202. X */
  203. X
  204. X/*
  205. X * Structure for regexp "program".  This is essentially a linear encoding
  206. X * of a nondeterministic finite-state machine (aka syntax charts or
  207. X * "railroad normal form" in parsing technology).  Each node is an opcode
  208. X * plus a "next" pointer, possibly plus an operand.  "Next" pointers of
  209. X * all nodes except BRANCH implement concatenation; a "next" pointer with
  210. X * a BRANCH on both ends of it is connecting two alternatives.  (Here we
  211. X * have one of the subtle syntax dependencies:  an individual BRANCH (as
  212. X * opposed to a collection of them) is never concatenated with anything
  213. X * because of operator precedence.)  The operand of some types of node is
  214. X * a literal string; for others, it is a node leading into a sub-FSM.  In
  215. X * particular, the operand of a BRANCH node is the first node of the branch.
  216. X * (NB this is *not* a tree structure:  the tail of the branch connects
  217. X * to the thing following the set of BRANCHes.)  The opcodes are:
  218. X */
  219. X
  220. X/* definition    number    opnd?    meaning */
  221. X#define    END    0    /* no    End of program. */
  222. X#define    BOL    1    /* no    Match "" at beginning of line. */
  223. X#define    EOL    2    /* no    Match "" at end of line. */
  224. X#define    ANY    3    /* no    Match any one character. */
  225. X#define    ANYOF    4    /* str    Match any character in this string. */
  226. X#define    ANYBUT    5    /* str    Match any character not in this string. */
  227. X#define    BRANCH    6    /* node    Match this alternative, or the next... */
  228. X#define    BACK    7    /* no    Match "", "next" ptr points backward. */
  229. X#define    EXACTLY    8    /* str    Match this string. */
  230. X#define    NOTHING    9    /* no    Match empty string. */
  231. X#define    STAR    10    /* node    Match this (simple) thing 0 or more times. */
  232. X#define    PLUS    11    /* node    Match this (simple) thing 1 or more times. */
  233. X#define    OPEN    20    /* no    Mark this point in input as start of #n. */
  234. X            /*    OPEN+1 is number 1, etc. */
  235. X#define    CLOSE    30    /* no    Analogous to OPEN. */
  236. X
  237. X/*
  238. X * Opcode notes:
  239. X *
  240. X * BRANCH    The set of branches constituting a single choice are hooked
  241. X *        together with their "next" pointers, since precedence prevents
  242. X *        anything being concatenated to any individual branch.  The
  243. X *        "next" pointer of the last BRANCH in a choice points to the
  244. X *        thing following the whole choice.  This is also where the
  245. X *        final "next" pointer of each individual branch points; each
  246. X *        branch starts with the operand node of a BRANCH node.
  247. X *
  248. X * BACK        Normal "next" pointers all implicitly point forward; BACK
  249. X *        exists to make loop structures possible.
  250. X *
  251. X * STAR,PLUS    '?', and complex '*' and '+', are implemented as circular
  252. X *        BRANCH structures using BACK.  Simple cases (one character
  253. X *        per match) are implemented with STAR and PLUS for speed
  254. X *        and to minimize recursive plunges.
  255. X *
  256. X * OPEN,CLOSE    ...are numbered at compile time.
  257. X */
  258. X
  259. X/*
  260. X * A node is one char of opcode followed by two chars of "next" pointer.
  261. X * "Next" pointers are stored as two 8-bit pieces, high order first.  The
  262. X * value is a positive offset from the opcode of the node containing it.
  263. X * An operand, if any, simply follows the node.  (Note that much of the
  264. X * code generation knows about this implicit relationship.)
  265. X *
  266. X * Using two bytes for the "next" pointer is vast overkill for most things,
  267. X * but allows patterns to get big without disasters.
  268. X */
  269. X#define    OP(p)    (*(p))
  270. X#define    NEXT(p)    (((*((p)+1)&0377)<<8) + *((p)+2)&0377)
  271. X#define    OPERAND(p)    ((p) + 3)
  272. X
  273. X/*
  274. X * See regmagic.h for one further detail of program structure.
  275. X */
  276. X
  277. X
  278. X/*
  279. X * Utility definitions.
  280. X */
  281. X#ifndef CHARBITS
  282. X#define    UCHARAT(p)    ((int)*(unsigned char *)(p))
  283. X#else
  284. X#define    UCHARAT(p)    ((int)*(p)&CHARBITS)
  285. X#endif
  286. X
  287. X#define    FAIL(m)    { regerror(m); return(NULL); }
  288. X#define    ISMULT(c)    ((c) == '*' || (c) == '+' || (c) == '?')
  289. X#define    META    "^$.[()|?+*\\"
  290. X
  291. X/*
  292. X * Flags to be passed up and down.
  293. X */
  294. X#define    HASWIDTH    01    /* Known never to match null string. */
  295. X#define    SIMPLE        02    /* Simple enough to be STAR/PLUS operand. */
  296. X#define    SPSTART        04    /* Starts with * or +. */
  297. X#define    WORST        0    /* Worst case. */
  298. X
  299. X/*
  300. X * Global work variables for regcomp().
  301. X */
  302. Xstatic char *regparse;        /* Input-scan pointer. */
  303. Xstatic int regnpar;        /* () count. */
  304. Xstatic char regdummy;
  305. Xstatic char *regcode;        /* Code-emit pointer; ®dummy = don't. */
  306. Xstatic long regsize;        /* Code size. */
  307. X
  308. X/*
  309. X * Forward declarations for regcomp()'s friends.
  310. X */
  311. X#ifndef STATIC
  312. X#define    STATIC    static
  313. X#endif
  314. XSTATIC char *reg();
  315. XSTATIC char *regbranch();
  316. XSTATIC char *regpiece();
  317. XSTATIC char *regatom();
  318. XSTATIC char *regnode();
  319. XSTATIC char *regnext();
  320. XSTATIC void regc();
  321. XSTATIC void reginsert();
  322. XSTATIC void regtail();
  323. XSTATIC void regoptail();
  324. X#ifdef STRCSPN
  325. XSTATIC int strcspn();
  326. X#endif
  327. X
  328. X/*
  329. X - regcomp - compile a regular expression into internal code
  330. X *
  331. X * We can't allocate space until we know how big the compiled form will be,
  332. X * but we can't compile it (and thus know how big it is) until we've got a
  333. X * place to put the code.  So we cheat:  we compile it twice, once with code
  334. X * generation turned off and size counting turned on, and once "for real".
  335. X * This also means that we don't allocate space until we are sure that the
  336. X * thing really will compile successfully, and we never have to move the
  337. X * code and thus invalidate pointers into it.  (Note that it has to be in
  338. X * one piece because free() must be able to free it all.)
  339. X *
  340. X * Beware that the optimization-preparation code in here knows about some
  341. X * of the structure of the compiled regexp.
  342. X */
  343. Xregexp *
  344. Xregcomp(exp)
  345. Xchar *exp;
  346. X{
  347. X    register regexp *r;
  348. X    register char *scan;
  349. X    register char *longest;
  350. X    register int len;
  351. X    int flags;
  352. X    extern char *malloc();
  353. X
  354. X    if (exp == NULL)
  355. X        FAIL("NULL argument");
  356. X
  357. X    /* First pass: determine size, legality. */
  358. X    regparse = exp;
  359. X    regnpar = 1;
  360. X    regsize = 0L;
  361. X    regcode = ®dummy;
  362. X    regc(MAGIC);
  363. X    if (reg(0, &flags) == NULL)
  364. X        return(NULL);
  365. X
  366. X    /* Small enough for pointer-storage convention? */
  367. X    if (regsize >= 32767L)        /* Probably could be 65535L. */
  368. X        FAIL("regexp too big");
  369. X
  370. X    /* Allocate space. */
  371. X    r = (regexp *)malloc(sizeof(regexp) + (unsigned)regsize);
  372. X    if (r == NULL)
  373. X        FAIL("out of space");
  374. X
  375. X    /* Second pass: emit code. */
  376. X    regparse = exp;
  377. X    regnpar = 1;
  378. X    regcode = r->program;
  379. X    regc(MAGIC);
  380. X    if (reg(0, &flags) == NULL)
  381. X        return(NULL);
  382. X
  383. X    /* Dig out information for optimizations. */
  384. X    r->regstart = '\0';    /* Worst-case defaults. */
  385. X    r->reganch = 0;
  386. X    r->regmust = NULL;
  387. X    r->regmlen = 0;
  388. X    scan = r->program+1;            /* First BRANCH. */
  389. X    if (OP(regnext(scan)) == END) {        /* Only one top-level choice. */
  390. X        scan = OPERAND(scan);
  391. X
  392. X        /* Starting-point info. */
  393. X        if (OP(scan) == EXACTLY)
  394. X            r->regstart = *OPERAND(scan);
  395. X        else if (OP(scan) == BOL)
  396. X            r->reganch++;
  397. X
  398. X        /*
  399. X         * If there's something expensive in the r.e., find the
  400. X         * longest literal string that must appear and make it the
  401. X         * regmust.  Resolve ties in favor of later strings, since
  402. X         * the regstart check works with the beginning of the r.e.
  403. X         * and avoiding duplication strengthens checking.  Not a
  404. X         * strong reason, but sufficient in the absence of others.
  405. X         */
  406. X        if (flags&SPSTART) {
  407. X            longest = NULL;
  408. X            len = 0;
  409. X            for (; scan != NULL; scan = regnext(scan))
  410. X                if (OP(scan) == EXACTLY && strlen(OPERAND(scan)) >= len) {
  411. X                    longest = OPERAND(scan);
  412. X                    len = strlen(OPERAND(scan));
  413. X                }
  414. X            r->regmust = longest;
  415. X            r->regmlen = len;
  416. X        }
  417. X    }
  418. X
  419. X    return(r);
  420. X}
  421. X
  422. X/*
  423. X - reg - regular expression, i.e. main body or parenthesized thing
  424. X *
  425. X * Caller must absorb opening parenthesis.
  426. X *
  427. X * Combining parenthesis handling with the base level of regular expression
  428. X * is a trifle forced, but the need to tie the tails of the branches to what
  429. X * follows makes it hard to avoid.
  430. X */
  431. Xstatic char *
  432. Xreg(paren, flagp)
  433. Xint paren;            /* Parenthesized? */
  434. Xint *flagp;
  435. X{
  436. X    register char *ret;
  437. X    register char *br;
  438. X    register char *ender;
  439. X    register int parno;
  440. X    int flags;
  441. X
  442. X    *flagp = HASWIDTH;    /* Tentatively. */
  443. X
  444. X    /* Make an OPEN node, if parenthesized. */
  445. X    if (paren) {
  446. X        if (regnpar >= NSUBEXP)
  447. X            FAIL("too many ()");
  448. X        parno = regnpar;
  449. X        regnpar++;
  450. X        ret = regnode(OPEN+parno);
  451. X    } else
  452. X        ret = NULL;
  453. X
  454. X    /* Pick up the branches, linking them together. */
  455. X    br = regbranch(&flags);
  456. X    if (br == NULL)
  457. X        return(NULL);
  458. X    if (ret != NULL)
  459. X        regtail(ret, br);    /* OPEN -> first. */
  460. X    else
  461. X        ret = br;
  462. X    if (!(flags&HASWIDTH))
  463. X        *flagp &= ~HASWIDTH;
  464. X    *flagp |= flags&SPSTART;
  465. X    while (*regparse == '|') {
  466. X        regparse++;
  467. X        br = regbranch(&flags);
  468. X        if (br == NULL)
  469. X            return(NULL);
  470. X        regtail(ret, br);    /* BRANCH -> BRANCH. */
  471. X        if (!(flags&HASWIDTH))
  472. X            *flagp &= ~HASWIDTH;
  473. X        *flagp |= flags&SPSTART;
  474. X    }
  475. X
  476. X    /* Make a closing node, and hook it on the end. */
  477. X    ender = regnode((paren) ? CLOSE+parno : END);    
  478. X    regtail(ret, ender);
  479. X
  480. X    /* Hook the tails of the branches to the closing node. */
  481. X    for (br = ret; br != NULL; br = regnext(br))
  482. X        regoptail(br, ender);
  483. X
  484. X    /* Check for proper termination. */
  485. X    if (paren && *regparse++ != ')') {
  486. X        FAIL("unmatched ()");
  487. X    } else if (!paren && *regparse != '\0') {
  488. X        if (*regparse == ')') {
  489. X            FAIL("unmatched ()");
  490. X        } else
  491. X            FAIL("junk on end");    /* "Can't happen". */
  492. X        /* NOTREACHED */
  493. X    }
  494. X
  495. X    return(ret);
  496. X}
  497. X
  498. X/*
  499. X - regbranch - one alternative of an | operator
  500. X *
  501. X * Implements the concatenation operator.
  502. X */
  503. Xstatic char *
  504. Xregbranch(flagp)
  505. Xint *flagp;
  506. X{
  507. X    register char *ret;
  508. X    register char *chain;
  509. X    register char *latest;
  510. X    int flags;
  511. X
  512. X    *flagp = WORST;        /* Tentatively. */
  513. X
  514. X    ret = regnode(BRANCH);
  515. X    chain = NULL;
  516. X    while (*regparse != '\0' && *regparse != '|' && *regparse != ')') {
  517. X        latest = regpiece(&flags);
  518. X        if (latest == NULL)
  519. X            return(NULL);
  520. X        *flagp |= flags&HASWIDTH;
  521. X        if (chain == NULL)    /* First piece. */
  522. X            *flagp |= flags&SPSTART;
  523. X        else
  524. X            regtail(chain, latest);
  525. X        chain = latest;
  526. X    }
  527. X    if (chain == NULL)    /* Loop ran zero times. */
  528. X        (void) regnode(NOTHING);
  529. X
  530. X    return(ret);
  531. X}
  532. X
  533. X/*
  534. X - regpiece - something followed by possible [*+?]
  535. X *
  536. X * Note that the branching code sequences used for ? and the general cases
  537. X * of * and + are somewhat optimized:  they use the same NOTHING node as
  538. X * both the endmarker for their branch list and the body of the last branch.
  539. X * It might seem that this node could be dispensed with entirely, but the
  540. X * endmarker role is not redundant.
  541. X */
  542. Xstatic char *
  543. Xregpiece(flagp)
  544. Xint *flagp;
  545. X{
  546. X    register char *ret;
  547. X    register char op;
  548. X    register char *next;
  549. X    int flags;
  550. X
  551. X    ret = regatom(&flags);
  552. X    if (ret == NULL)
  553. X        return(NULL);
  554. X
  555. X    op = *regparse;
  556. X    if (!ISMULT(op)) {
  557. X        *flagp = flags;
  558. X        return(ret);
  559. X    }
  560. X
  561. X    if (!(flags&HASWIDTH) && op != '?')
  562. X        FAIL("*+ operand could be empty");
  563. X    *flagp = (op != '+') ? (WORST|SPSTART) : (WORST|HASWIDTH);
  564. X
  565. X    if (op == '*' && (flags&SIMPLE))
  566. X        reginsert(STAR, ret);
  567. X    else if (op == '*') {
  568. X        /* Emit x* as (x&|), where & means "self". */
  569. X        reginsert(BRANCH, ret);            /* Either x */
  570. X        regoptail(ret, regnode(BACK));        /* and loop */
  571. X        regoptail(ret, ret);            /* back */
  572. X        regtail(ret, regnode(BRANCH));        /* or */
  573. X        regtail(ret, regnode(NOTHING));        /* null. */
  574. X    } else if (op == '+' && (flags&SIMPLE))
  575. X        reginsert(PLUS, ret);
  576. X    else if (op == '+') {
  577. X        /* Emit x+ as x(&|), where & means "self". */
  578. X        next = regnode(BRANCH);            /* Either */
  579. X        regtail(ret, next);
  580. X        regtail(regnode(BACK), ret);        /* loop back */
  581. X        regtail(next, regnode(BRANCH));        /* or */
  582. X        regtail(ret, regnode(NOTHING));        /* null. */
  583. X    } else if (op == '?') {
  584. X        /* Emit x? as (x|) */
  585. X        reginsert(BRANCH, ret);            /* Either x */
  586. X        regtail(ret, regnode(BRANCH));        /* or */
  587. X        next = regnode(NOTHING);        /* null. */
  588. X        regtail(ret, next);
  589. X        regoptail(ret, next);
  590. X    }
  591. X    regparse++;
  592. X    if (ISMULT(*regparse))
  593. X        FAIL("nested *?+");
  594. X
  595. X    return(ret);
  596. X}
  597. X
  598. X/*
  599. X - regatom - the lowest level
  600. X *
  601. X * Optimization:  gobbles an entire sequence of ordinary characters so that
  602. X * it can turn them into a single node, which is smaller to store and
  603. X * faster to run.  Backslashed characters are exceptions, each becoming a
  604. X * separate node; the code is simpler that way and it's not worth fixing.
  605. X */
  606. Xstatic char *
  607. Xregatom(flagp)
  608. Xint *flagp;
  609. X{
  610. X    register char *ret;
  611. X    int flags;
  612. X
  613. X    *flagp = WORST;        /* Tentatively. */
  614. X
  615. X    switch (*regparse++) {
  616. X    case '^':
  617. X        ret = regnode(BOL);
  618. X        break;
  619. X    case '$':
  620. X        ret = regnode(EOL);
  621. X        break;
  622. X    case '.':
  623. X        ret = regnode(ANY);
  624. X        *flagp |= HASWIDTH|SIMPLE;
  625. X        break;
  626. X    case '[': {
  627. X            register int class;
  628. X            register int classend;
  629. X
  630. X            if (*regparse == '^') {    /* Complement of range. */
  631. X                ret = regnode(ANYBUT);
  632. X                regparse++;
  633. X            } else
  634. X                ret = regnode(ANYOF);
  635. X            if (*regparse == ']' || *regparse == '-')
  636. X                regc(*regparse++);
  637. X            while (*regparse != '\0' && *regparse != ']') {
  638. X                if (*regparse == '-') {
  639. X                    regparse++;
  640. X                    if (*regparse == ']' || *regparse == '\0')
  641. X                        regc('-');
  642. X                    else {
  643. X                        class = UCHARAT(regparse-2)+1;
  644. X                        classend = UCHARAT(regparse);
  645. X                        if (class > classend+1)
  646. X                            FAIL("invalid [] range");
  647. X                        for (; class <= classend; class++)
  648. X                            regc(class);
  649. X                        regparse++;
  650. X                    }
  651. X                } else
  652. X                    regc(*regparse++);
  653. X            }
  654. X            regc('\0');
  655. X            if (*regparse != ']')
  656. X                FAIL("unmatched []");
  657. X            regparse++;
  658. X            *flagp |= HASWIDTH|SIMPLE;
  659. X        }
  660. X        break;
  661. X    case '(':
  662. X        ret = reg(1, &flags);
  663. X        if (ret == NULL)
  664. X            return(NULL);
  665. X        *flagp |= flags&(HASWIDTH|SPSTART);
  666. X        break;
  667. X    case '\0':
  668. X    case '|':
  669. X    case ')':
  670. X        FAIL("internal urp");    /* Supposed to be caught earlier. */
  671. X        break;
  672. X    case '?':
  673. X    case '+':
  674. X    case '*':
  675. X        FAIL("?+* follows nothing");
  676. X        break;
  677. X    case '\\':
  678. X        if (*regparse == '\0')
  679. X            FAIL("trailing \\");
  680. X        ret = regnode(EXACTLY);
  681. X        regc(*regparse++);
  682. X        regc('\0');
  683. X        *flagp |= HASWIDTH|SIMPLE;
  684. X        break;
  685. X    default: {
  686. X            register int len;
  687. X            register char ender;
  688. X
  689. X            regparse--;
  690. X            len = strcspn(regparse, META);
  691. X            if (len <= 0)
  692. X                FAIL("internal disaster");
  693. X            ender = *(regparse+len);
  694. X            if (len > 1 && ISMULT(ender))
  695. X                len--;        /* Back off clear of ?+* operand. */
  696. X            *flagp |= HASWIDTH;
  697. X            if (len == 1)
  698. X                *flagp |= SIMPLE;
  699. X            ret = regnode(EXACTLY);
  700. X            while (len > 0) {
  701. X                regc(*regparse++);
  702. X                len--;
  703. X            }
  704. X            regc('\0');
  705. X        }
  706. X        break;
  707. X    }
  708. X
  709. X    return(ret);
  710. X}
  711. X
  712. X/*
  713. X - regnode - emit a node
  714. X */
  715. Xstatic char *            /* Location. */
  716. Xregnode(op)
  717. Xchar op;
  718. X{
  719. X    register char *ret;
  720. X    register char *ptr;
  721. X
  722. X    ret = regcode;
  723. X    if (ret == ®dummy) {
  724. X        regsize += 3;
  725. X        return(ret);
  726. X    }
  727. X
  728. X    ptr = ret;
  729. X    *ptr++ = op;
  730. X    *ptr++ = '\0';        /* Null "next" pointer. */
  731. X    *ptr++ = '\0';
  732. X    regcode = ptr;
  733. X
  734. X    return(ret);
  735. X}
  736. X
  737. X/*
  738. X - regc - emit (if appropriate) a byte of code
  739. X */
  740. Xstatic void
  741. Xregc(b)
  742. Xchar b;
  743. X{
  744. X    if (regcode != ®dummy)
  745. X        *regcode++ = b;
  746. X    else
  747. X        regsize++;
  748. X}
  749. X
  750. X/*
  751. X - reginsert - insert an operator in front of already-emitted operand
  752. X *
  753. X * Means relocating the operand.
  754. X */
  755. Xstatic void
  756. Xreginsert(op, opnd)
  757. Xchar op;
  758. Xchar *opnd;
  759. X{
  760. X    register char *src;
  761. X    register char *dst;
  762. X    register char *place;
  763. X
  764. X    if (regcode == ®dummy) {
  765. X        regsize += 3;
  766. X        return;
  767. X    }
  768. X
  769. X    src = regcode;
  770. X    regcode += 3;
  771. X    dst = regcode;
  772. X    while (src > opnd)
  773. X        *--dst = *--src;
  774. X
  775. X    place = opnd;        /* Op node, where operand used to be. */
  776. X    *place++ = op;
  777. X    *place++ = '\0';
  778. X    *place++ = '\0';
  779. X}
  780. X
  781. X/*
  782. X - regtail - set the next-pointer at the end of a node chain
  783. X */
  784. Xstatic void
  785. Xregtail(p, val)
  786. Xchar *p;
  787. Xchar *val;
  788. X{
  789. X    register char *scan;
  790. X    register char *temp;
  791. X    register int offset;
  792. X
  793. X    if (p == ®dummy)
  794. X        return;
  795. X
  796. X    /* Find last node. */
  797. X    scan = p;
  798. X    for (;;) {
  799. X        temp = regnext(scan);
  800. X        if (temp == NULL)
  801. X            break;
  802. X        scan = temp;
  803. X    }
  804. X
  805. X    if (OP(scan) == BACK)
  806. X        offset = scan - val;
  807. X    else
  808. X        offset = val - scan;
  809. X    *(scan+1) = (offset>>8)&0377;
  810. X    *(scan+2) = offset&0377;
  811. X}
  812. X
  813. X/*
  814. X - regoptail - regtail on operand of first argument; nop if operandless
  815. X */
  816. Xstatic void
  817. Xregoptail(p, val)
  818. Xchar *p;
  819. Xchar *val;
  820. X{
  821. X    /* "Operandless" and "op != BRANCH" are synonymous in practice. */
  822. X    if (p == NULL || p == ®dummy || OP(p) != BRANCH)
  823. X        return;
  824. X    regtail(OPERAND(p), val);
  825. X}
  826. X
  827. X/*
  828. X * regexec and friends
  829. X */
  830. X
  831. X/*
  832. X * Global work variables for regexec().
  833. X */
  834. Xstatic char *reginput;        /* String-input pointer. */
  835. Xstatic char *regbol;        /* Beginning of input, for ^ check. */
  836. Xstatic char **regstartp;    /* Pointer to startp array. */
  837. Xstatic char **regendp;        /* Ditto for endp. */
  838. X
  839. X/*
  840. X * Forwards.
  841. X */
  842. XSTATIC int regtry();
  843. XSTATIC int regmatch();
  844. XSTATIC int regrepeat();
  845. X
  846. X#ifdef DEBUG
  847. Xint regnarrate = 0;
  848. Xvoid regdump();
  849. XSTATIC char *regprop();
  850. X#endif
  851. X
  852. X/*
  853. X - regexec - match a regexp against a string
  854. X */
  855. Xint
  856. Xregexec(prog, string)
  857. Xregister regexp *prog;
  858. Xregister char *string;
  859. X{
  860. X    register char *s;
  861. X    extern char *strchr();
  862. X
  863. X    /* Be paranoid... */
  864. X    if (prog == NULL || string == NULL) {
  865. X        regerror("NULL parameter");
  866. X        return(0);
  867. X    }
  868. X
  869. X    /* Check validity of program. */
  870. X    if (UCHARAT(prog->program) != MAGIC) {
  871. X        regerror("corrupted program");
  872. X        return(0);
  873. X    }
  874. X
  875. X    /* If there is a "must appear" string, look for it. */
  876. X    if (prog->regmust != NULL) {
  877. X        s = string;
  878. X        while ((s = strchr(s, prog->regmust[0])) != NULL) {
  879. X            if (strncmp(s, prog->regmust, prog->regmlen) == 0)
  880. X                break;    /* Found it. */
  881. X            s++;
  882. X        }
  883. X        if (s == NULL)    /* Not present. */
  884. X            return(0);
  885. X    }
  886. X
  887. X    /* Mark beginning of line for ^ . */
  888. X    regbol = string;
  889. X
  890. X    /* Simplest case:  anchored match need be tried only once. */
  891. X    if (prog->reganch)
  892. X        return(regtry(prog, string));
  893. X
  894. X    /* Messy cases:  unanchored match. */
  895. X    s = string;
  896. X    if (prog->regstart != '\0')
  897. X        /* We know what char it must start with. */
  898. X        while ((s = strchr(s, prog->regstart)) != NULL) {
  899. X            if (regtry(prog, s))
  900. X                return(1);
  901. X            s++;
  902. X        }
  903. X    else
  904. X        /* We don't -- general case. */
  905. X        do {
  906. X            if (regtry(prog, s))
  907. X                return(1);
  908. X        } while (*s++ != '\0');
  909. X
  910. X    /* Failure. */
  911. X    return(0);
  912. X}
  913. X
  914. X/*
  915. X - regtry - try match at specific point
  916. X */
  917. Xstatic int            /* 0 failure, 1 success */
  918. Xregtry(prog, string)
  919. Xregexp *prog;
  920. Xchar *string;
  921. X{
  922. X    register int i;
  923. X    register char **sp;
  924. X    register char **ep;
  925. X
  926. X    reginput = string;
  927. X    regstartp = prog->startp;
  928. X    regendp = prog->endp;
  929. X
  930. X    sp = prog->startp;
  931. X    ep = prog->endp;
  932. X    for (i = NSUBEXP; i > 0; i--) {
  933. X        *sp++ = NULL;
  934. X        *ep++ = NULL;
  935. X    }
  936. X    if (regmatch(prog->program + 1)) {
  937. X        prog->startp[0] = string;
  938. X        prog->endp[0] = reginput;
  939. X        return(1);
  940. X    } else
  941. X        return(0);
  942. X}
  943. X
  944. X/*
  945. X - regmatch - main matching routine
  946. X *
  947. X * Conceptually the strategy is simple:  check to see whether the current
  948. X * node matches, call self recursively to see whether the rest matches,
  949. X * and then act accordingly.  In practice we make some effort to avoid
  950. X * recursion, in particular by going through "ordinary" nodes (that don't
  951. X * need to know whether the rest of the match failed) by a loop instead of
  952. X * by recursion.
  953. X */
  954. Xstatic int            /* 0 failure, 1 success */
  955. Xregmatch(prog)
  956. Xchar *prog;
  957. X{
  958. X    register char *scan;    /* Current node. */
  959. X    char *next;        /* Next node. */
  960. X    extern char *strchr();
  961. X
  962. X    scan = prog;
  963. X#ifdef DEBUG
  964. X    if (scan != NULL && regnarrate)
  965. X        fprintf(stderr, "%s(\n", regprop(scan));
  966. X#endif
  967. X    while (scan != NULL) {
  968. X#ifdef DEBUG
  969. X        if (regnarrate)
  970. X            fprintf(stderr, "%s...\n", regprop(scan));
  971. X#endif
  972. X        next = regnext(scan);
  973. X
  974. X        switch (OP(scan)) {
  975. X        case BOL:
  976. X            if (reginput != regbol)
  977. X                return(0);
  978. X            break;
  979. X        case EOL:
  980. X            if (*reginput != '\0')
  981. X                return(0);
  982. X            break;
  983. X        case ANY:
  984. X            if (*reginput == '\0')
  985. X                return(0);
  986. X            reginput++;
  987. X            break;
  988. X        case EXACTLY: {
  989. X                register int len;
  990. X                register char *opnd;
  991. X
  992. X                opnd = OPERAND(scan);
  993. X                /* Inline the first character, for speed. */
  994. X                if (*opnd != *reginput)
  995. X                    return(0);
  996. X                len = strlen(opnd);
  997. X                if (len > 1 && strncmp(opnd, reginput, len) != 0)
  998. X                    return(0);
  999. X                reginput += len;
  1000. X            }
  1001. X            break;
  1002. X        case ANYOF:
  1003. X            if (*reginput == '\0' || strchr(OPERAND(scan), *reginput) == NULL)
  1004. X                return(0);
  1005. X            reginput++;
  1006. X            break;
  1007. X        case ANYBUT:
  1008. X            if (*reginput == '\0' || strchr(OPERAND(scan), *reginput) != NULL)
  1009. X                return(0);
  1010. X            reginput++;
  1011. X            break;
  1012. X        case NOTHING:
  1013. X            break;
  1014. X        case BACK:
  1015. X            break;
  1016. X        case OPEN+1:
  1017. X        case OPEN+2:
  1018. X        case OPEN+3:
  1019. X        case OPEN+4:
  1020. X        case OPEN+5:
  1021. X        case OPEN+6:
  1022. X        case OPEN+7:
  1023. X        case OPEN+8:
  1024. X        case OPEN+9: {
  1025. X                register int no;
  1026. X                register char *save;
  1027. X
  1028. X                no = OP(scan) - OPEN;
  1029. X                save = reginput;
  1030. X
  1031. X                if (regmatch(next)) {
  1032. X                    /*
  1033. X                     * Don't set startp if some later
  1034. X                     * invocation of the same parentheses
  1035. X                     * already has.
  1036. X                     */
  1037. X                    if (regstartp[no] == NULL)
  1038. X                        regstartp[no] = save;
  1039. X                    return(1);
  1040. X                } else
  1041. X                    return(0);
  1042. X            }
  1043. X            break;
  1044. X        case CLOSE+1:
  1045. X        case CLOSE+2:
  1046. X        case CLOSE+3:
  1047. X        case CLOSE+4:
  1048. X        case CLOSE+5:
  1049. X        case CLOSE+6:
  1050. X        case CLOSE+7:
  1051. X        case CLOSE+8:
  1052. X        case CLOSE+9: {
  1053. X                register int no;
  1054. X                register char *save;
  1055. X
  1056. X                no = OP(scan) - CLOSE;
  1057. X                save = reginput;
  1058. X
  1059. X                if (regmatch(next)) {
  1060. X                    /*
  1061. X                     * Don't set endp if some later
  1062. X                     * invocation of the same parentheses
  1063. X                     * already has.
  1064. X                     */
  1065. X                    if (regendp[no] == NULL)
  1066. X                        regendp[no] = save;
  1067. X                    return(1);
  1068. X                } else
  1069. X                    return(0);
  1070. X            }
  1071. X            break;
  1072. X        case BRANCH: {
  1073. X                register char *save;
  1074. X
  1075. X                if (OP(next) != BRANCH)        /* No choice. */
  1076. X                    next = OPERAND(scan);    /* Avoid recursion. */
  1077. X                else {
  1078. X                    do {
  1079. X                        save = reginput;
  1080. X                        if (regmatch(OPERAND(scan)))
  1081. X                            return(1);
  1082. X                        reginput = save;
  1083. X                        scan = regnext(scan);
  1084. X                    } while (scan != NULL && OP(scan) == BRANCH);
  1085. X                    return(0);
  1086. X                    /* NOTREACHED */
  1087. X                }
  1088. X            }
  1089. X            break;
  1090. X        case STAR:
  1091. X        case PLUS: {
  1092. X                register char nextch;
  1093. X                register int no;
  1094. X                register char *save;
  1095. X                register int min;
  1096. X
  1097. X                /*
  1098. X                 * Lookahead to avoid useless match attempts
  1099. X                 * when we know what character comes next.
  1100. X                 */
  1101. X                nextch = '\0';
  1102. X                if (OP(next) == EXACTLY)
  1103. X                    nextch = *OPERAND(next);
  1104. X                min = (OP(scan) == STAR) ? 0 : 1;
  1105. X                save = reginput;
  1106. X                no = regrepeat(OPERAND(scan));
  1107. X                while (no >= min) {
  1108. X                    /* If it could work, try it. */
  1109. X                    if (nextch == '\0' || *reginput == nextch)
  1110. X                        if (regmatch(next))
  1111. X                            return(1);
  1112. X                    /* Couldn't or didn't -- back up. */
  1113. X                    no--;
  1114. X                    reginput = save + no;
  1115. X                }
  1116. X                return(0);
  1117. X            }
  1118. X            break;
  1119. X        case END:
  1120. X            return(1);    /* Success! */
  1121. X            break;
  1122. X        default:
  1123. X            regerror("memory corruption");
  1124. X            return(0);
  1125. X            break;
  1126. X        }
  1127. X
  1128. X        scan = next;
  1129. X    }
  1130. X
  1131. X    /*
  1132. X     * We get here only if there's trouble -- normally "case END" is
  1133. X     * the terminating point.
  1134. X     */
  1135. X    regerror("corrupted pointers");
  1136. X    return(0);
  1137. X}
  1138. X
  1139. X/*
  1140. X - regrepeat - repeatedly match something simple, report how many
  1141. X */
  1142. Xstatic int
  1143. Xregrepeat(p)
  1144. Xchar *p;
  1145. X{
  1146. X    register int count = 0;
  1147. X    register char *scan;
  1148. X    register char *opnd;
  1149. X
  1150. X    scan = reginput;
  1151. X    opnd = OPERAND(p);
  1152. X    switch (OP(p)) {
  1153. X    case ANY:
  1154. X        count = strlen(scan);
  1155. X        scan += count;
  1156. X        break;
  1157. X    case EXACTLY:
  1158. X        while (*opnd == *scan) {
  1159. X            count++;
  1160. X            scan++;
  1161. X        }
  1162. X        break;
  1163. X    case ANYOF:
  1164. X        while (*scan != '\0' && strchr(opnd, *scan) != NULL) {
  1165. X            count++;
  1166. X            scan++;
  1167. X        }
  1168. X        break;
  1169. X    case ANYBUT:
  1170. X        while (*scan != '\0' && strchr(opnd, *scan) == NULL) {
  1171. X            count++;
  1172. X            scan++;
  1173. X        }
  1174. X        break;
  1175. X    default:        /* Oh dear.  Called inappropriately. */
  1176. X        regerror("internal foulup");
  1177. X        count = 0;    /* Best compromise. */
  1178. X        break;
  1179. X    }
  1180. X    reginput = scan;
  1181. X
  1182. X    return(count);
  1183. X}
  1184. X
  1185. X/*
  1186. X - regnext - dig the "next" pointer out of a node
  1187. X */
  1188. Xstatic char *
  1189. Xregnext(p)
  1190. Xregister char *p;
  1191. X{
  1192. X    register int offset;
  1193. X
  1194. X    if (p == ®dummy)
  1195. X        return(NULL);
  1196. X
  1197. X    offset = NEXT(p);
  1198. X    if (offset == 0)
  1199. X        return(NULL);
  1200. X
  1201. X    if (OP(p) == BACK)
  1202. X        return(p-offset);
  1203. X    else
  1204. X        return(p+offset);
  1205. X}
  1206. X
  1207. X#ifdef DEBUG
  1208. X
  1209. XSTATIC char *regprop();
  1210. X
  1211. X/*
  1212. X - regdump - dump a regexp onto stdout in vaguely comprehensible form
  1213. X */
  1214. Xvoid
  1215. Xregdump(r)
  1216. Xregexp *r;
  1217. X{
  1218. X    register char *s;
  1219. X    register char op = EXACTLY;    /* Arbitrary non-END op. */
  1220. X    register char *next;
  1221. X    extern char *strchr();
  1222. X
  1223. X
  1224. X    s = r->program + 1;
  1225. X    while (op != END) {    /* While that wasn't END last time... */
  1226. X        op = OP(s);
  1227. X        printf("%2d%s", s-r->program, regprop(s));    /* Where, what. */
  1228. X        next = regnext(s);
  1229. X        if (next == NULL)        /* Next ptr. */
  1230. X            printf("(0)");
  1231. X        else 
  1232. X            printf("(%d)", (s-r->program)+(next-s));
  1233. X        s += 3;
  1234. X        if (op == ANYOF || op == ANYBUT || op == EXACTLY) {
  1235. X            /* Literal string, where present. */
  1236. X            while (*s != '\0') {
  1237. X                putchar(*s);
  1238. X                s++;
  1239. X            }
  1240. X            s++;
  1241. X        }
  1242. X        putchar('\n');
  1243. X    }
  1244. X
  1245. X    /* Header fields of interest. */
  1246. X    if (r->regstart != '\0')
  1247. X        printf("start `%c' ", r->regstart);
  1248. X    if (r->reganch)
  1249. X        printf("anchored ");
  1250. X    if (r->regmust != NULL)
  1251. X        printf("must have \"%s\"", r->regmust);
  1252. X    printf("\n");
  1253. X}
  1254. X
  1255. X/*
  1256. X - regprop - printable representation of opcode
  1257. X */
  1258. Xstatic char *
  1259. Xregprop(op)
  1260. Xchar *op;
  1261. X{
  1262. X    register char *p;
  1263. X    static char buf[50];
  1264. X
  1265. X    (void) strcpy(buf, ":");
  1266. X
  1267. X    switch (OP(op)) {
  1268. X    case BOL:
  1269. X        p = "BOL";
  1270. X        break;
  1271. X    case EOL:
  1272. X        p = "EOL";
  1273. X        break;
  1274. X    case ANY:
  1275. X        p = "ANY";
  1276. X        break;
  1277. X    case ANYOF:
  1278. X        p = "ANYOF";
  1279. X        break;
  1280. X    case ANYBUT:
  1281. X        p = "ANYBUT";
  1282. X        break;
  1283. X    case BRANCH:
  1284. X        p = "BRANCH";
  1285. X        break;
  1286. X    case EXACTLY:
  1287. X        p = "EXACTLY";
  1288. X        break;
  1289. X    case NOTHING:
  1290. X        p = "NOTHING";
  1291. X        break;
  1292. X    case BACK:
  1293. X        p = "BACK";
  1294. X        break;
  1295. X    case END:
  1296. X        p = "END";
  1297. X        break;
  1298. X    case OPEN+1:
  1299. X    case OPEN+2:
  1300. X    case OPEN+3:
  1301. X    case OPEN+4:
  1302. X    case OPEN+5:
  1303. X    case OPEN+6:
  1304. X    case OPEN+7:
  1305. X    case OPEN+8:
  1306. X    case OPEN+9:
  1307. X        sprintf(buf+strlen(buf), "OPEN%d", OP(op)-OPEN);
  1308. X        p = NULL;
  1309. X        break;
  1310. X    case CLOSE+1:
  1311. X    case CLOSE+2:
  1312. X    case CLOSE+3:
  1313. X    case CLOSE+4:
  1314. X    case CLOSE+5:
  1315. X    case CLOSE+6:
  1316. X    case CLOSE+7:
  1317. X    case CLOSE+8:
  1318. X    case CLOSE+9:
  1319. X        sprintf(buf+strlen(buf), "CLOSE%d", OP(op)-CLOSE);
  1320. X        p = NULL;
  1321. X        break;
  1322. X    case STAR:
  1323. X        p = "STAR";
  1324. X        break;
  1325. X    case PLUS:
  1326. X        p = "PLUS";
  1327. X        break;
  1328. X    default:
  1329. X        regerror("corrupted opcode");
  1330. X        break;
  1331. X    }
  1332. X    if (p != NULL)
  1333. X        (void) strcat(buf, p);
  1334. X    return(buf);
  1335. X}
  1336. X#endif
  1337. X
  1338. X/*
  1339. X * The following is provided for those people who do not have strcspn() in
  1340. X * their C libraries.  They should get off their butts and do something
  1341. X * about it; at least one public-domain implementation of those (highly
  1342. X * useful) string routines has been published on Usenet.
  1343. X */
  1344. X#ifdef STRCSPN
  1345. X/*
  1346. X * strcspn - find length of initial segment of s1 consisting entirely
  1347. X * of characters not from s2
  1348. X */
  1349. X
  1350. Xstatic int
  1351. Xstrcspn(s1, s2)
  1352. Xchar *s1;
  1353. Xchar *s2;
  1354. X{
  1355. X    register char *scan1;
  1356. X    register char *scan2;
  1357. X    register int count;
  1358. X
  1359. X    count = 0;
  1360. X    for (scan1 = s1; *scan1 != '\0'; scan1++) {
  1361. X        for (scan2 = s2; *scan2 != '\0';)    /* ++ moved down. */
  1362. X            if (*scan1 == *scan2++)
  1363. X                return(count);
  1364. X        count++;
  1365. X    }
  1366. X    return(count);
  1367. X}
  1368. X#endif
  1369. END_OF_regexp.c
  1370. if test 27732 -ne `wc -c <regexp.c`; then
  1371.     echo shar: \"regexp.c\" unpacked with wrong size!
  1372. fi
  1373. # end of overwriting check
  1374. fi
  1375. if test -f wns.c -a "${1}" != "-c" ; then 
  1376.   echo shar: Will not over-write existing file \"wns.c\"
  1377. else
  1378. echo shar: Extracting \"wns.c\" \(12950 characters\)
  1379. sed "s/^X//" >wns.c <<'END_OF_wns.c'
  1380. X/* wns.c - Search for string and print window of lines around it.
  1381. X
  1382. X        Nov 19 1984     Mark Mallett   (mem@zinn.MV.COM)
  1383. X
  1384. Xmem    860224    Modified to do r/e (regular expression) parsing on unix
  1385. Xmem    860324    Added -f, -n; added code to number lines correctly on
  1386. X        output.
  1387. Xmem    870325    Added support for regcmp()/regex() style regular expression
  1388. X        library; redid some conditionals to provide better mix'n'match.
  1389. Xmem    870326    Don't try to print the filename if reading from stdin.
  1390. X        Add -w option.  Fix a small problem which occasionally allowed
  1391. X        the separator to come out between adjacent lines of the file.
  1392. Xmem    871119    Fix semantics of call to regcmp(): the NULL terminating the
  1393. X        argument list was missing.  It worked, but probably only
  1394. X        due to some bizarre coincidence.
  1395. X
  1396. X    Changes by Mark Rinfret for Amiga (mrr@amanpt1.ZONE1.COM)
  1397. X
  1398. Xmrr    881009    Use V8 regexp routines (since I had 'em)
  1399. X
  1400. X*/
  1401. X
  1402. X/* The appropriate defines are done in the makefile */
  1403. X/* #define    OS_UNIX */    /* Define this for unix systems */
  1404. X/* #define    SYSINC */    /* Define this for sys/ include hierarchy */
  1405. X/* #define    REGEX */    /* Define this for re_comp/re_exec library */
  1406. X/* #define    REGCMP */    /* Define this to use regcmp/regex */
  1407. X/* #define    REGCOMP */    /* Define this to use regcomp/regexec */
  1408. X/* #define    OS_CPM */    /* Define this for CP/M-80 */
  1409. X
  1410. X
  1411. X/* Don't touch these */
  1412. X#define    NOREGEXP        /* Set this for no regular expression */
  1413. X#ifdef    REGEX
  1414. X#undef    NOREGEXP
  1415. X#endif    REGEX
  1416. X
  1417. X#ifdef    REGCMP
  1418. X#undef    NOREGEXP
  1419. X#endif    REGCMP
  1420. X
  1421. X#ifdef REGCOMP
  1422. X#undef NOREGEXP
  1423. X#endif
  1424. X
  1425. X
  1426. X#ifdef OS_CPM
  1427. X#include "stdio.h"
  1428. X#include "ctype.h"
  1429. X#endif OS_CPM
  1430. X
  1431. X#ifdef OS_UNIX
  1432. X#include <stdio.h>
  1433. X#include <ctype.h>
  1434. X
  1435. X#ifdef    SYSINC
  1436. X#include <sys/types.h>
  1437. X#include <sys/dir.h>
  1438. X#else    /* !SYSINC */
  1439. X#ifndef AMIGA
  1440. X#include <types.h>
  1441. X#include <dir.h>
  1442. X#endif
  1443. X#endif    SYSINC
  1444. X#endif OS_UNIX
  1445. X
  1446. Xchar *calloc();
  1447. Xchar *fgets();
  1448. X
  1449. X/* Local definitions */
  1450. X
  1451. X#ifndef    NULL
  1452. X#define    NULL    ((char *)0)
  1453. X#endif    NULL
  1454. X
  1455. X#ifndef NUL
  1456. X#define NUL     '\000'
  1457. X#endif
  1458. X
  1459. X#ifndef TRUE
  1460. X#define TRUE    1
  1461. X#define FALSE   0
  1462. X#endif
  1463. X
  1464. X
  1465. X/* Internal data declared global */
  1466. X
  1467. X
  1468. X/* Internal routines */
  1469. X
  1470. X
  1471. X/* External data */
  1472. X
  1473. X
  1474. X/* External routines */
  1475. X
  1476. X#ifdef    REGEX            /* re_comp/ re_exec */
  1477. Xextern    char    *re_comp();        /* r/e compile */
  1478. Xextern    int    re_exec();        /* r/e exec */
  1479. X#endif    REGEX
  1480. X
  1481. X#ifdef    REGCMP            /* regcmp/regex */
  1482. Xextern    char    *regcmp();        /* r/e compile */
  1483. Xextern    char    *regex();        /* r/e exec */
  1484. X#endif    REGCMP
  1485. X
  1486. X#ifdef REGCOMP            /* regcomp/regexec */
  1487. Xextern char    *regcomp();
  1488. Xextern char    *regexec();
  1489. X#endif
  1490. X
  1491. X
  1492. X/* Local data */
  1493. X
  1494. Xstatic  int     Debug={FALSE};          /* Debug enabled flag */
  1495. Xstatic  int     Lcur = {0};             /* Current line (in Lines array) */
  1496. Xstatic  char    **Lines = {(char **)NULL};       /* Lines pointer array */
  1497. Xstatic  int     Linlen = {100};         /* Line length */
  1498. Xstatic  int     Lone = {0};             /* Line one (in Lines array) */
  1499. Xstatic    int    Nmr = {0};        /* Number of matched regions */
  1500. Xstatic  char    *Pat = {NULL};          /* Pattern */
  1501. Xstatic    char    Shwfile = {TRUE};    /* Show file name... */
  1502. Xstatic    char    Shwline = {TRUE};    /* Show line number */
  1503. Xstatic  int     Waft = {0};             /* Window after */
  1504. Xstatic  int     Wbef = {0};             /* Window before */
  1505. Xstatic  int     Wsiz = {0};             /* Window size */
  1506. X
  1507. X#ifdef    REGEX        /* regex style r/e manipulations */
  1508. Xchar        *Re;        /* Result from re_comp() */
  1509. X#endif    REGEX
  1510. X
  1511. X#ifdef    REGCMP        /* regcmp style r/e */
  1512. Xchar        *Re;        /* Result from regcmp() */
  1513. X#endif    REGCMP
  1514. X
  1515. X#ifdef REGCOMP
  1516. Xchar        *Re;        /* Result from regcomp() */
  1517. X#endif REGCOMP
  1518. X
  1519. Xmain (argc, argv)
  1520. X
  1521. Xint             argc;           /* Argument count */
  1522. Xchar            **argv;         /* Argument values */
  1523. X
  1524. X{
  1525. Xint             i;              /* Scratch */
  1526. Xint             n;              /* Scratch again */
  1527. Xint             c;              /* A character */
  1528. Xchar            *aptr;          /* Argument pointer */
  1529. Xint             nf;             /* number of files on command line */
  1530. X
  1531. Xnf = 0;                         /* No files on line */
  1532. X
  1533. Xfor (i = 1; i < argc; i++)      /* Look at args */
  1534. X    {
  1535. X    if (argv[i][0] != '-')      /* If option */
  1536. X        {
  1537. X        if (Pat == NULL)        /* If no pattern yet given */
  1538. X        {
  1539. X            Pat = argv[i];      /*  point here */
  1540. X#ifdef    REGEX
  1541. X        if ((Re = re_comp(Pat)) != NULL)
  1542. X            {
  1543. X        fprintf(stderr, "wns: %s\n", re);
  1544. X        exit(1);
  1545. X        }
  1546. X#endif    REGEX
  1547. X
  1548. X#ifdef    REGCMP
  1549. X        if ((Re = regcmp(Pat, NULL)) == NULL)
  1550. X            {
  1551. X        fprintf(stderr, "wns: error in regular expression.\n");
  1552. X        exit(1);
  1553. X        }
  1554. X#endif    REGCMP
  1555. X
  1556. X#ifdef    REGCOMP
  1557. X        if ((Re = regcomp(Pat, NULL)) == NULL)
  1558. X            {
  1559. X        fprintf(stderr, "wns: error in regular expression.\n");
  1560. X        exit(1);
  1561. X        }
  1562. X#endif    REGCOMP
  1563. X
  1564. X        }
  1565. X        else                    /* This must be a file to search */
  1566. X            {
  1567. X#ifdef AMIGA
  1568. X            /* On the Amiga, we may have to do wildcard expansion. */
  1569. X#ifdef AZTEC_C
  1570. X            /* Aztec provides a method for this.  I don't know what
  1571. X             * Lattice provides.  Sorry.
  1572. X             */
  1573. X            char *scdir();        /* Aztec C wildcard expansion */
  1574. X            char *fName;        /* filename back from scdir() */
  1575. X            int  isWild;
  1576. X            char testChar;
  1577. X
  1578. X            /* Because the Aztec scdir() routine is so slow (due to 
  1579. X             * directory scanning), avoid its use if possible.  Only call
  1580. X             * scdir() if we have a filename with wildcard characters.
  1581. X             */
  1582. X            isWild = 0;
  1583. X            for (fName = argv[i]; testChar = *fName++; )
  1584. X                if (testChar == '*' || testChar == '?') {
  1585. X                    ++isWild;    /* Filename has wildcards. */
  1586. X                    break;
  1587. X                }
  1588. X
  1589. X            if (isWild) {
  1590. X                while (fName = scdir(argv[i])) {
  1591. X                    nf++;
  1592. X                    dosrch(fName);
  1593. X                }
  1594. X            }
  1595. X            else {
  1596. X                nf++;
  1597. X                dosrch(argv[i]);
  1598. X            }
  1599. X#else
  1600. X            /* Lattice variant of wildcard handling goes here. */
  1601. X            nf++;
  1602. X            dosrch(argv[i]);
  1603. X#endif
  1604. X#else
  1605. X            nf++;               /* Count it */
  1606. X            dosrch (argv[i]);   /* Search */
  1607. X#endif
  1608. X            }
  1609. X        }
  1610. X
  1611. X    else                        /* Option char */
  1612. X        {
  1613. X        c = argv[i][1];         /* Get option char */
  1614. X        if (isupper(c))         /* Trap idiot definition of tolower */
  1615. X            c = tolower(c);     /* Don't care about case */
  1616. X        n = i;
  1617. X        aptr = NULL;            /* Find arg, if any */
  1618. X        if (argv[i][2] != NUL)
  1619. X            {
  1620. X            aptr = &argv[i][2];
  1621. X            n = i;              /* Where to set i if we use this arg */
  1622. X            }
  1623. X        else if (i < argc-1)    /* use next.. */
  1624. X            {
  1625. X            n = i+1;
  1626. X            aptr = argv[n];
  1627. X            }
  1628. X
  1629. X        switch (c)              /* Process the option */
  1630. X            {
  1631. X            case 'a':           /* Lines after */
  1632. X                Waft = atoi (aptr);
  1633. X                Lines = NULL;
  1634. X                i = n;
  1635. X                break;
  1636. X
  1637. X            case 'b':           /* Lines before */
  1638. X                Wbef = atoi (aptr);
  1639. X                Lines = (char **)NULL;
  1640. X                i = n;
  1641. X                break;
  1642. X
  1643. X            case 'd':           /* Enable debugging */
  1644. X                Debug = TRUE;
  1645. X                break;
  1646. X
  1647. X        case 'f':        /* Suppress filename on output */
  1648. X            Shwfile = FALSE;
  1649. X        break;
  1650. X
  1651. X            case 'l':           /* Line length */
  1652. X                Linlen = atoi (aptr);
  1653. X                Lines = NULL;
  1654. X                i = n;
  1655. X                break;
  1656. X
  1657. X        case 'n':        /* Suppress line number on output */
  1658. X            Shwline = FALSE;
  1659. X        break;
  1660. X
  1661. X            case 'w':           /* Window: lines before and after */
  1662. X                Waft = Wbef = atoi (aptr);
  1663. X                Lines = NULL;
  1664. X                i = n;
  1665. X                break;
  1666. X
  1667. X            default:
  1668. X                fprintf (stderr, "Invalid option %s\n",argv[i]);
  1669. X                exit(1);
  1670. X            }
  1671. X        }
  1672. X    }
  1673. X
  1674. Xif ( Pat == NULL )        /* If no pattern given */
  1675. X    {
  1676. X    fprintf(stderr, 
  1677. X"usage: wns [-a n] [-b n] [-d] [-f] [-l n] [-n] [-w n] pattern [filename... ]\n");
  1678. X    exit(1);
  1679. X    }
  1680. X
  1681. Xif (nf == 0)                    /* No files processed ? */
  1682. X    dosrch (NULL);              /* Do standard input */
  1683. X
  1684. X    exit(0);
  1685. X}
  1686. X/*
  1687. X
  1688. X*//* dosrch (ifnm)
  1689. X
  1690. X        Perform the search
  1691. X
  1692. XAccepts :
  1693. X
  1694. X        ifn             Input file name
  1695. X
  1696. X
  1697. XReturns :
  1698. X
  1699. X
  1700. X*/
  1701. X
  1702. Xdosrch (ifnm)
  1703. X
  1704. Xchar            *ifnm;          /* Input filelname */
  1705. X
  1706. X{
  1707. XFILE            *ifp;           /* Input fp */
  1708. Xchar            *lptr;          /* Line pointer */
  1709. Xint             i;              /* Scratch */
  1710. Xint             prtaft;         /* Print-after count */
  1711. Xint             linnum;         /* Line number */
  1712. Xint        nlb;        /* Number of lines buffered */
  1713. X
  1714. Xif (ifnm != NULL)               /* If file name given */
  1715. X    {
  1716. X    ifp = fopen (ifnm, "r");    /* Open it for read access */
  1717. X    if (ifp == NULL)
  1718. X        {
  1719. X        fprintf (stderr, "Can not open file %s\n", ifnm);
  1720. X        return;
  1721. X        }
  1722. X    }
  1723. Xelse
  1724. X    ifp = stdin;
  1725. X
  1726. Xif (Lines == NULL)              /* If no line table allocated.. */
  1727. X    {
  1728. X    Wsiz = Wbef+2;              /* Determine total window size */
  1729. X    Lines = (char **) calloc (Wsiz, sizeof (char *));
  1730. X                                /* Allocate pointer table */
  1731. X    for (i = 0; i < Wsiz; i++)  /* Allocate line buffers */
  1732. X        Lines[i] = (char *) calloc (Linlen, sizeof(char));
  1733. X    }
  1734. X
  1735. XLcur = Lone = 0;                /* Setup line pointers */
  1736. Xnlb = 0;            /* No lines buffered */
  1737. Xlinnum = 0;                     /* Line number is zero */
  1738. Xprtaft = -(Wbef+1);        /* Make sure separator given first time */
  1739. X
  1740. Xfor (;;)                        /* Loop through the file */
  1741. X    {
  1742. X    lptr = Lines[Lcur];         /* Get pointer to current line */
  1743. X    if (++Lcur == Wsiz)         /* Bump curr pointer and wrap */
  1744. X        Lcur = 0;               /*  if hit end */
  1745. X    if (Lone == Lcur)           /* If wrapped to beginning of window */
  1746. X        if (++Lone == Wsiz)     /*  Bump beginning */
  1747. X            Lone = 0;           /*   and wrap if hit end */
  1748. X
  1749. X    if (fgets (lptr, Linlen, ifp) != lptr)
  1750. X        break;                  /*  if end of file */
  1751. X
  1752. X    linnum++;                   /* Count line number */
  1753. X    if (matlin (lptr))          /* If matching line */
  1754. X        {
  1755. X        if (prtaft < (-Wbef) )  /* Check for separator needed */
  1756. X            if ( (Nmr++ > 0 ) && ((Wbef > 0) || (Waft > 0)) )
  1757. X                printf ("-------------------\n");
  1758. X        while (Lone != Lcur)    /* Until we close the window */
  1759. X            {
  1760. X            shwlin (ifnm, linnum-nlb, Lines[Lone]);
  1761. X                                /* Show the line */
  1762. X            if (++Lone == Wsiz)
  1763. X                Lone = 0;
  1764. X        nlb--;
  1765. X            }
  1766. X    nlb = 0;        /* No lines buffered */
  1767. X        prtaft = Waft;          /* Print n lines after */
  1768. X        }
  1769. X
  1770. X    else                        /* Didn't match */
  1771. X        {
  1772. X        if (prtaft-- > 0)       /* If must print lines after */
  1773. X            {
  1774. X            shwlin (ifnm, linnum, lptr);
  1775. X                                /* Show the line */
  1776. X            Lone = Lcur;        /* Match pointers */
  1777. X            }
  1778. X    else if (nlb < Wbef)    /* Count lines buffered */
  1779. X        nlb++;
  1780. X        }
  1781. X    }
  1782. X
  1783. Xif (ifnm != NULL)
  1784. X    fclose (ifp);
  1785. X}
  1786. X/*
  1787. X
  1788. X*//* shwlin (fnm, linnum, line)
  1789. X
  1790. X        Show a matching line
  1791. X
  1792. X
  1793. XAccepts :
  1794. X
  1795. X        fnm             File name
  1796. X
  1797. X        linnum          Line number
  1798. X
  1799. X        line            Line to show
  1800. X
  1801. X
  1802. XReturns :
  1803. X
  1804. X
  1805. X*/
  1806. X
  1807. Xshwlin (fnm, linnum, line)
  1808. X
  1809. Xchar            *fnm;           /* File name */
  1810. Xint             linnum;         /* Line number */
  1811. Xchar            *line;          /* Line (with newline at end) to print */
  1812. X
  1813. X{
  1814. Xif (Shwfile && ( fnm != NULL) )
  1815. X    printf("%s%s", fnm, Shwline?" ":":");
  1816. Xif (Shwline)
  1817. X    printf("@%05d%:", linnum);
  1818. Xprintf ("%s", line);
  1819. X}
  1820. X/*
  1821. X
  1822. X*//* matlin (line)
  1823. X
  1824. X        Perform match against pattern and line
  1825. X
  1826. X
  1827. XAccepts :
  1828. X
  1829. X        line            Address of line to match
  1830. X
  1831. X
  1832. XReturns :
  1833. X
  1834. X        <value>         TRUE if match
  1835. X                        FALSE if not
  1836. X
  1837. X
  1838. X*/
  1839. X
  1840. X
  1841. Xint matlin (line)
  1842. X
  1843. Xchar            *line;          /* Line to match */
  1844. X
  1845. X{
  1846. Xint        rtncode;        /* Return value from this routine */
  1847. X
  1848. X
  1849. X#ifdef    NOREGEXP
  1850. Xchar            *pptr, *lptr, *tlptr;
  1851. Xint             c1,c2;
  1852. X#endif    NOREGEXP
  1853. X
  1854. Xif (Debug)
  1855. X    printf ("Matching %s against %s", Pat, line);
  1856. X
  1857. X#ifdef    REGEX
  1858. Xrtncode = re_exec(line);    /* Hand off to r/e evaluator */
  1859. X#endif    REGEX
  1860. X
  1861. X#ifdef    REGCMP
  1862. Xrtncode = ( regex( Re, line ) != NULL );
  1863. X#endif    REGCMP
  1864. X
  1865. X#ifdef REGCOMP
  1866. Xrtncode = ( regexec( Re, line ) != NULL );
  1867. X#endif REGCOMP
  1868. X
  1869. X#ifdef    NOREGEX        /* Have to do menial comparison.. */
  1870. Xlptr = line;                    /* Init line pointer */
  1871. X
  1872. Xfor ( rtncode = -1; rtncode < 0; )
  1873. X    {
  1874. X    tlptr = lptr++;             /* Get temp ptr to line */
  1875. X    pptr = Pat;                 /* Get ptr to pattern */
  1876. X    while (TRUE)
  1877. X        {
  1878. X        if ((c1 = *pptr++) == NUL)
  1879. X            {
  1880. X        rtncode = 1;    /* GOOD return value */
  1881. X        break;
  1882. X            }
  1883. X        if ((c2 = *tlptr++) == NUL)
  1884. X            {
  1885. X        rtncode = 0;    /* BAD return value */
  1886. X        break;
  1887. X            }
  1888. X        if (isupper(c1))
  1889. X            c1 = tolower(c1);
  1890. X        if (isupper(c2))
  1891. X            c2 = tolower(c2);
  1892. X        if (c1 != c2)
  1893. X            break;
  1894. X        }
  1895. X    }
  1896. X#endif    NOREGEX
  1897. X
  1898. X
  1899. Xif (Debug)
  1900. X    printf("matlin returned %s\n", rtncode?"TRUE":"FALSE");
  1901. Xreturn(rtncode);
  1902. X}
  1903. X
  1904. X
  1905. END_OF_wns.c
  1906. if test 12950 -ne `wc -c <wns.c`; then
  1907.     echo shar: \"wns.c\" unpacked with wrong size!
  1908. fi
  1909. # end of overwriting check
  1910. fi
  1911. if test -f wns.man -a "${1}" != "-c" ; then 
  1912.   echo shar: Will not over-write existing file \"wns.man\"
  1913. else
  1914. echo shar: Extracting \"wns.man\" \(2415 characters\)
  1915. sed "s/^X//" >wns.man <<'END_OF_wns.man'
  1916. X
  1917. X
  1918. X
  1919. X     WNS(1)                                                     WNS(1)
  1920. X
  1921. X
  1922. X
  1923. X     NAME
  1924. X          wns - windowing search
  1925. X
  1926. X     SYNOPSIS
  1927. X          wns [-a nnn] [-b nnn] [-l nnn] [-w nnn] pattern [file ... ]
  1928. X
  1929. X     DESCRIPTION
  1930. X          _w_n_s searches through a file or list of files for occurances
  1931. X          of a particular pattern, and prints a window of lines around
  1932. X          each match point.
  1933. X
  1934. X          Options which may be given are as follows:
  1935. X
  1936. X          -a nnn
  1937. X               (After) specifies that nnn lines following the matching
  1938. X               line will be printed.  default is 0.
  1939. X
  1940. X          -b nnn
  1941. X               (Before) specifies that nnn lines preceding the
  1942. X               matching line will be printed.  default is 0.
  1943. X
  1944. X          -d   Enables debugging information.  Not a very interesting
  1945. X               option.
  1946. X
  1947. X          -f   Suppress printing of the filename on each output line.
  1948. X
  1949. X          -l nnn
  1950. X               Sets the maximum line length to nnn.  Lines longer than
  1951. X               this will be truncated to this length before attempting
  1952. X               to match them to the pattern as well as when printing
  1953. X               them.  Default is 100.
  1954. X
  1955. X          -n   Suppress printing of the line number on each output
  1956. X               line.
  1957. X
  1958. X          -w nnn
  1959. X               Sets the window size to nnn.  This is the same as -a
  1960. X               nnn -b nnn.
  1961. X
  1962. X          _w_n_s outputs lines in the following format:
  1963. X
  1964. X          filename @nnnnn: text
  1965. X
  1966. X          where _f_i_l_e_n_a_m_e is the name of the file containing the
  1967. X          matching text and may be suppressed with the -f option,
  1968. X          _l_n_n_n_n is the line number of the displayed line and may be
  1969. X          suppressed with the -n option, and _t_e_x_t is the line from the
  1970. X          file.  Additionally, if the total window size is greater
  1971. X          than 1 (that is, more than zero lines before or after), then
  1972. X          non-adjacent text areas are separated by a short dashed
  1973. X          line.
  1974. X
  1975. X
  1976. X
  1977. X
  1978. X     Page 1                                          (printed 9/23/88)
  1979. X
  1980. X
  1981. X
  1982. X
  1983. X
  1984. X
  1985. X     WNS(1)                                                     WNS(1)
  1986. X
  1987. X
  1988. X
  1989. X     FILES
  1990. X          /usr/local/bin/wns /usr/local/src/wns/*
  1991. X
  1992. X     CREDITS TO
  1993. X          M. Mallett  (mem@zinn.MV.COM)
  1994. X
  1995. X     BUGS
  1996. X          You tell me..
  1997. X
  1998. X
  1999. X
  2000. X
  2001. X
  2002. X
  2003. X
  2004. X
  2005. X
  2006. X
  2007. X
  2008. X
  2009. X
  2010. X
  2011. X
  2012. X
  2013. X
  2014. X
  2015. X
  2016. X
  2017. X
  2018. X
  2019. X
  2020. X
  2021. X
  2022. X
  2023. X
  2024. X
  2025. X
  2026. X
  2027. X
  2028. X
  2029. X
  2030. X
  2031. X
  2032. X
  2033. X
  2034. X
  2035. X
  2036. X
  2037. X
  2038. X
  2039. X
  2040. X
  2041. X
  2042. X
  2043. X
  2044. X     Page 2                                          (printed 9/23/88)
  2045. X
  2046. X
  2047. X
  2048. END_OF_wns.man
  2049. echo shar: 23 control characters may be missing from \"wns.man\"
  2050. if test 2415 -ne `wc -c <wns.man`; then
  2051.     echo shar: \"wns.man\" unpacked with wrong size!
  2052. fi
  2053. # end of overwriting check
  2054. fi
  2055. if test -f wns.1 -a "${1}" != "-c" ; then 
  2056.   echo shar: Will not over-write existing file \"wns.1\"
  2057. else
  2058. echo shar: Extracting \"wns.1\" \(1655 characters\)
  2059. sed "s/^X//" >wns.1 <<'END_OF_wns.1'
  2060. X.TH WNS 1
  2061. X.SH NAME
  2062. Xwns \- windowing search
  2063. X.SH SYNOPSIS
  2064. X.B wns
  2065. X[-a nnn]
  2066. X[-b nnn]
  2067. X[-l nnn]
  2068. X[-w nnn]
  2069. Xpattern
  2070. X[file ... ]
  2071. X.SH DESCRIPTION
  2072. X.I wns
  2073. Xsearches through a file or list of files for occurances of a particular
  2074. Xpattern, and prints a window of lines around each match point.
  2075. X.PP
  2076. XOptions which may be given are as follows:
  2077. X.TP
  2078. X.B \-a\ nnn
  2079. X(After) specifies that nnn lines following the matching line will be
  2080. Xprinted.  default is 0.
  2081. X.TP
  2082. X.B \-b\ nnn
  2083. X(Before) specifies that nnn lines preceding the matching line will be
  2084. Xprinted.  default is 0.
  2085. X.TP
  2086. X.B \-d
  2087. XEnables debugging information.  Not a very interesting option.
  2088. X.TP
  2089. X.B \-f
  2090. XSuppress printing of the filename on each output line.
  2091. X.TP
  2092. X.B \-l\ nnn
  2093. XSets the maximum line length to nnn.  Lines longer than this will be
  2094. Xtruncated to this length before attempting to match them to the pattern as
  2095. Xwell as when printing them.  Default is 100.
  2096. X.TP
  2097. X.B \-n
  2098. XSuppress printing of the line number on each output line.
  2099. X.TP
  2100. X.B \-w\ nnn
  2101. XSets the window size to nnn.  This is the same as -a nnn -b nnn.
  2102. X.PP
  2103. X.I wns
  2104. Xoutputs lines in the following format:
  2105. X.PP
  2106. Xfilename @nnnnn: text
  2107. X.PP
  2108. Xwhere
  2109. X.I filename
  2110. Xis the name of the file containing the matching text and may be suppressed
  2111. Xwith the -f option,
  2112. X.I lnnnn
  2113. Xis the line number of the displayed line and may be suppressed with the
  2114. X-n option, and
  2115. X.I text
  2116. Xis the line from the file.
  2117. XAdditionally, if the total window size is greater than 1 (that is, more than
  2118. Xzero lines before or after), then non-adjacent text areas are separated by
  2119. Xa short dashed line.
  2120. X.SH FILES
  2121. X/usr/local/bin/wns /usr/local/src/wns/*
  2122. X.SH "CREDITS TO"
  2123. XM. Mallett  (mem@zinn.MV.COM)
  2124. X.SH BUGS
  2125. XYou tell me..
  2126. END_OF_wns.1
  2127. if test 1655 -ne `wc -c <wns.1`; then
  2128.     echo shar: \"wns.1\" unpacked with wrong size!
  2129. fi
  2130. # end of overwriting check
  2131. fi
  2132. echo shar: End of archive 1 \(of 1\).
  2133. cp /dev/null ark1isdone
  2134. MISSING=""
  2135. for I in 1 ; do
  2136.     if test ! -f ark${I}isdone ; then
  2137.     MISSING="${MISSING} ${I}"
  2138.     fi
  2139. done
  2140. if test "${MISSING}" = "" ; then
  2141.     echo You have unpacked all 1 archives.
  2142.     rm -f ark[1-9]isdone
  2143. else
  2144.     echo You still need to unpack the following archives:
  2145.     echo "        " ${MISSING}
  2146. fi
  2147. ##  End of shell archive.
  2148. exit 0
  2149.  
  2150.  
  2151. -- 
  2152. Bob Page, U of Lowell CS Dept.  page@swan.ulowell.edu  ulowell!page
  2153. "I can't tell the difference between ABC News and Hill Street Blues" -Bono
  2154.